/*
 * @ : Copyright (c) 2021 Phytium Information Technology, Inc. 
 *  
 * SPDX-License-Identifier: Apache-2.0.
 * 
 * @Date: 2021-06-21 14:11:09
 * @LastEditTime: 2021-09-06 14:57:37
 * @Description:  This files is for 
 * 
 * @Modify History: 
 *  Ver   Who        Date         Changes
 * ----- ------     --------    --------------------------------------
 */

#include "parameters.h"
#include "generic_timer.h"
#include "aarch32.h"
#include "sdkconfig.h"

#ifndef SDK_CONFIG_H__
    #warning "Please include sdkconfig.h"
#endif

#ifdef CONFIG_USE_SYS_TICK
#include "ft_assert.h"
#include "interrupt.h"
//#include "gicv3.h"

static volatile u32 genericTick;
#endif

#define AARCH32_CNTP_CTL_ENABLE_MASK (1ul << 0)
#define AARCH32_CNTP_CTL_INTERRUPT_MASK (1ul << 1)

void GenericTimerStart(void)
{
    u32 ctrl = aarch32_cntp_ctl_get();

    if (!(ctrl & AARCH32_CNTP_CTL_ENABLE_MASK))
    {
        ctrl |= AARCH32_CNTP_CTL_ENABLE_MASK;
        aarch32_cntp_ctl_set(ctrl);
    }
}

void GenericTimerStop(void)
{
    u32 ctrl = aarch32_cntp_ctl_get();
    if ((ctrl & AARCH32_CNTP_CTL_ENABLE_MASK))
    {
        ctrl &= ~AARCH32_CNTP_CTL_ENABLE_MASK;
        aarch32_cntp_ctl_set(ctrl);
    }
}

void GenericTimerInterruptEnable(void)
{
    u32 ctrl = aarch32_cntp_ctl_get();
    if (ctrl & AARCH32_CNTP_CTL_INTERRUPT_MASK)
    {
        ctrl &= ~AARCH32_CNTP_CTL_INTERRUPT_MASK;
        aarch32_cntp_ctl_set(ctrl);
    }
}

void GenericTimerInterruptDisable(void)
{
    u64 ctrl = aarch32_cntp_ctl_get();
    if (!(ctrl & AARCH32_CNTP_CTL_INTERRUPT_MASK))
    {
        ctrl |= AARCH32_CNTP_CTL_INTERRUPT_MASK;
        aarch32_cntp_ctl_set(ctrl);
    }
}

u32 GenericTimerFrequecy(void)
{
    u32 rate = aarch32_cntfrq_get();
    return (rate != 0) ? rate : 1000000;
}

u64 GenericTimerRead(void)
{
    return aarch32_cntpct_get();
}

void GenericTimerCompare(u32 interval)
{
    aarch32_cntp_tval_set(interval);
}

#ifdef CONFIG_USE_SYS_TICK
static void GenericTimerClearTickIntr(u32 tickRateHz)
{
    GenericTimerCompare(GenericTimerFrequecy() / tickRateHz);
}

static void GenericTimerTickIntrHandler(s32 vector, void *param)
{
    u32 tickRateHz = (u32)param;
    (void)vector;
    genericTick++; /* tick */
    GenericTimerClearTickIntr(tickRateHz);  /* clear tick intrrupt */
}
#endif

void GenericTimerSetupSystick(u32 tickRateHz, GenericTimerTickHandler tickHandler, u32 intrPrority)
{
#ifdef CONFIG_USE_SYS_TICK
    u32 cntFrq;

    /* disable timer and get system frequency */
    GenericTimerStop();
    cntFrq = GenericTimerFrequecy();

    /* set tick rate */
    GenericTimerCompare(cntFrq / tickRateHz);
    GenericTimerInterruptEnable();

    /* set generic timer intrrupt */
    InterruptSetPriority(GENERIC_TIMER_NS_IRQ_NUM, intrPrority);

    /* install tick handler */
    if (NULL == tickHandler)
    {
        InterruptInstall(GENERIC_TIMER_NS_IRQ_NUM, GenericTimerTickIntrHandler,
                        (void *)tickRateHz, "GenericTimerTick");
    }
    else
    {
        InterruptInstall(GENERIC_TIMER_NS_IRQ_NUM, tickHandler,
                        (void *)tickRateHz, "GenericTimerTick");        
    }


    /* enable intrrupt */
    InterruptUmask(GENERIC_TIMER_NS_IRQ_NUM);
    GenericTimerStart();
#endif
}

u32 GenericGetTick(void)
{
#ifdef CONFIG_USE_SYS_TICK
    return genericTick;
#else
    return 0xffU;
#endif
}